package com.zhou.cloud.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.zhou.cloud.config.UuidProperties;
import com.zhou.cloud.service.IGeneratorUuidService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.text.MessageFormat;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Collections;

/**
 * 参考：https://blog.csdn.net/weixin_51472505/article/details/126389359
 * @descrition: redis实现 uuid生成
 * uuid : 64位 long类型
 * 组成部分：
 * 1 位： 确定位0 保证是long类型
 * 2-14：zoneid 范围（0-8191) 13位
 * 15-29:时间偏移量（单位是天）当前时间-初始配置时间(2020-01-01)， 15位
 * 30-64:自增长(0-34359738367) 35位 （当前这位全区共享，还可以细分位单区共享）
 * @author: zhouyongjun
 * @date: 2022/10/27
 **/
@Service("redisUuidService")
@Slf4j
public class RedisGeneratorUuidServiceImpl implements IGeneratorUuidService {
    private static final String SCRIPT_TIME = "local a=redis.call('TIME'); return (a[1]*1000000+a[2])/1000";
    private static final String REDIS_KEY_FORMAT = "uuid::generator::{0}";
    @Autowired
    RedisTemplate redisTemplate;
    @Autowired
    UuidProperties uuidProperties;
    @Override
    public Long generatorUuid() {
        /*Long uuid =*//**/
        long newDay  = DateUtil.date().getTime()/(24*60*60*1000);
        long offset = newDay-uuidProperties.getOffset();
        if(offset < 0) {
            offset = 0;
        }
        long zoneId = uuidProperties.getZoneId();
        // 2.1.获取当前日期，精确到天
        String key = MessageFormat.format(REDIS_KEY_FORMAT,DateUtil.date().toString("yyyy-MM-dd"));
        Long increment = redisTemplate.opsForValue().increment(key,1);
        //64位，首位位0, 2-14:zoneid 15-29 30-64
        long uuid = zoneId << (uuidProperties.getMaxBitCount() - 1 -uuidProperties.getDateTimeBitCount())
                | offset << (uuidProperties.getMaxBitCount() - 1 -uuidProperties.getDateTimeBitCount()-uuidProperties.getZoneBitCount())
                | increment;
        log.warn("generator uuid : {} bit:{}",uuid,Long.toBinaryString(uuid));
        System.err.println(MessageFormat.format("generator uuid : {0} bit:{1},len={2}",uuid,Long.toBinaryString(uuid),Long.toBinaryString(uuid).toCharArray().length));
        return uuid;
    }

    /**
     * 获取redis当前时间戳，13位
     * @return
     */
    public Long currentTimeMillis() {
        final DefaultRedisScript<Long> script = new DefaultRedisScript<>(SCRIPT_TIME, Long.class);
        return (Long) redisTemplate.execute(script, Collections.EMPTY_LIST);
    }
}
